from .taskrunner import TaskRunner
import ma.const
import ma.log
import os
import ma.commons.core.constants as constants
import sys
import pickle


class ReduceTaskRunner(TaskRunner):
    
    def __init__(self, tip_info, user_module_name, user_class_name):
        
        TaskRunner.__init__(self, tip_info, user_module_name, user_class_name)
        
        #this is the dict to which the user function will emit keys and 
        #reduced values tuples
        #the struct is key -> list_of_values
        #this is the key value dict that will persist for the life of this 
        # reduceTIP as files are read one by one by the map and the key value 
        # pairs emitted will be appended to it and then finally written to a 
        # file
        self.key_value_dict = {}
        
        self.__log = ma.log.get_logger("ma.codes")
        
    
    def startTask(self):
        """This func is called to start the user defined code as a separate 
        process
        """
        raise NotImplementedError('This function is defined by each individual implementation')
            
        
    def writeOutputToLocalFile(self):
        """This function writes the output to the output file specified by the
        XML. The output would be in the form of a dictionary
        """
        
        #working out a reduce output file path name
        self.output_dest_dir = ma.const.JobsXmlData.get_filepath_str_data(ma.const.xml_local_output_temp_dir, 
                                                                    self.tip_info.job_id)
        
        output_filepath = self.output_dest_dir + os.sep + \
                ma.const.JobsXmlData.get_str_data(ma.const.xml_reduce_output_filename, self.tip_info.job_id, self.tip_info.task_id)
                
        try:
            self.__log.info('Starting to write reduce %d output: %s', self.tip_info.task_id, output_filepath)
            fd = open(output_filepath, "w+")
            fd.write(str(self.key_value_dict))
            fd.close()
            self.__log.info('Written reduce %d output: %s', self.tip_info.task_id, output_filepath)
            return True
        except IOError as err_msg:
            self.__log.error('Error while writing reduce output task-id %d, job-id %d: %s', self.tip_info.task_id, self.tip_info.job_id, err_msg)
            return False

        
    def writeKeysOutputFiles(self, fd, compute_temp_path):
        """This function write each key on the comma separate file to a 
        separate key files
        """

        list_of_keys_input = []
        
        input_read_buffer = ma.const.JobsXmlData.get_int_data(ma.const.xml_reduce_inp_read_size, self.tip_info.job_id)
        
        buff = fd.readline(input_read_buffer)
        while buff != '':
            idx = buff.find(":")
            key = buff[:idx]
            buff = buff[idx+1:]
            
            # add key to the list of keys
            list_of_keys_input.append(key)
            
            # append or make new key file
            key_file = compute_temp_path + key
            if not os.path.exists(key_file):
                fd_kf = open(key_file, 'w+')
            else:
                fd_kf = open(key_file, 'a+')
                fd_kf.write(', ')
            
            # iterate till all input shifted to the key file
            while buff[-1] != '\n':
                fd_kf.write(buff)
                buff = fd.readline(input_read_buffer)
            fd_kf.write(buff[:-1])
            fd_kf.close()
            
            # read next line
            buff = fd.readline(input_read_buffer)
            
        return list_of_keys_input 
 
